//
//  Context.cpp
//  LightBasic
//
//  Created by Albert on 19/03/2011.
//  Copyright 2011 LightBasic Development Team. All rights reserved.
//

#include "Context.h"

using namespace std;
using namespace lbc;

/**
 * cleanup
 */
Context::~Context()
{
    for (std::vector<SourceFile*>::iterator it = m_opensources.begin(); it != m_opensources.end(); it++) {
        delete *it;
    }
}


/**
 * Add resource
 */
void Context::Add(std::string const &path, Context::ResourceType type)
{
    FS::path source;
    switch (type) {
        case TypeGlobalPath:
        case TypeLibraryPath:
        case TypeSourcePath:
            source = ResolveDir(path);
            break;
        case TypeSource:
            source = ResolveFile(path, m_resources[Context::TypeSourcePath]);
            break;
        case TypeLibrary:
            source = ResolveFile(path, m_resources[Context::TypeLibraryPath]);
            break;
        default:
            throw Exception("Invalid ResourceType");
            break;
    }
    
    // add to the container
    ResourceContainer & rct = m_resources[type];
    if (std::find(rct.begin(), rct.end(), source) == rct.end()) {
        rct.push_back(source);
    }
}


/**
 * Get available resources
 */
const ResourceContainer & Context::GetResources(ResourceType type) const
{
    if (type >= Context::TypeCount) {
        throw Exception("Invalid ResourceType");
    }
    return m_resources[type];
}


/**
 * Open or get already existing source
 */
Source & Context::GetSource(const FS::path & path)
{
    for (std::vector<SourceFile*>::iterator it = m_opensources.begin(); it != m_opensources.end(); it++) {
        if ((*it)->GetName() == path.string()) {
            return **it;
        }
    }
    SourceFile * file = new SourceFile(path);
    m_opensources.push_back(file);
    return *file;
}


/**
 * Resolve directory
 */
FS::path Context::ResolveDir(const std::string & dir) const
{
    // invalid ?
    if (dir.size() == 0) {
        throw Exception("No Directory");
    }
    
    // the path
    FS::path path;
    
    // remove trailing slash
    char ch = dir[dir.size() - 1];
    if (ch == '\\' || ch == '/') {
        path = dir.substr(0, dir.size() - 1);
    } else {
        path = dir;
    }
    
    // if nor absolute then check against registered global directories
    if (!path.is_absolute()) {
        const ResourceContainer & cont = m_resources[TypeGlobalPath];
        for(ResourceContainer::const_iterator iter = cont.begin(); iter != cont.end(); iter++) {
            FS::path tmp = *iter / path;
            if (FS::is_directory(tmp)) {
                return tmp.normalize();
            }
        }
    } else if (FS::is_directory(path)) {
        return path.normalize();
    }
    
    // not found
    throw Exception("Directory '" + dir + "' not found" );
}


/**
 * Resolve file path
 */
FS::path Context::ResolveFile(const std::string & file, const ResourceContainer & cnt) const
{
    FS::path path(file);
    
    // is absolute path?
    if (!path.is_absolute()) {
        // search the container
        for(ResourceContainer::const_iterator it = cnt.begin(); it != cnt.end(); it++) {
            FS::path tmp = *it / path;
            if (FS::is_regular_file(tmp)) {
                return tmp.normalize();
            }
        }
        // search global container
        const ResourceContainer & global = m_resources[TypeGlobalPath];
        for(ResourceContainer::const_iterator it = global.begin(); it != global.end(); it++) {
            FS::path tmp = *it / path;
            if (FS::is_regular_file(tmp)) {
                return tmp.normalize();
            }
        }
    } else if (FS::is_regular_file(path)) {
        return path.normalize();
    }
    
    // not found
    throw Exception("File '" + file + "' not found");
}











